// Author: Domien Nowicki

#include "MapWidget.h"
#include "MapLandItem.h"
#include <math.h>

using std::min;
using std::max;

const qreal MapWidget::CENTERSCALE = 0.6;

MapWidget::MapWidget(QWidget *parent)
{
	// Initialize the scene
	InitializeScene();
}

MapWidget::MapWidget(const MapWidget& rhs)
{
	// Initialize the scene
	InitializeScene();
	Copy(rhs);

	// Center the scene
	Center();
}

MapWidget::MapWidget(QWidget *parent, const Map& rhs)
{
	// Initialize the scene
	InitializeScene();
	Copy(rhs);

	// Center the scene
	Center();
}

MapWidget::~MapWidget()
{
}

void MapWidget::InitializeScene()
{
	// Initialize the graphics scene
    QGraphicsScene *scene = new QGraphicsScene(this);

	// Setup scene specific stuff
    scene->setItemIndexMethod(QGraphicsScene::NoIndex);
    setScene(scene);
    setCacheMode(CacheBackground);
    setRenderHint(QPainter::Antialiasing);
    setTransformationAnchor(AnchorUnderMouse);
    setResizeAnchor(AnchorViewCenter);
    setAlignment(Qt::AlignCenter );
}

void MapWidget::Center()
{
	// Center the scene rectangle
	setSceneRect( boundingRect() );
	// Fit the scene rect in the widget window
	fitInView( boundingRect() , Qt::KeepAspectRatio);

	// Scale it by a bit
	scale(CENTERSCALE, CENTERSCALE);
}


bool MapWidget::LoadFromFile(const std::string& filename)
{
	bool result = Map::LoadFromFile(filename);

	if (result)
	{
		// If loaded successfully, center the map
		Center();
	}

	return result;
}

Land* MapWidget::InsertLand(MapLandItem *item)
{
	// Connect the clicked province signal so we can propagate it back to here
	QObject::connect(item, SIGNAL(clickedProvince(Land*, Province*)), this, SLOT(slotClickedProvince(Land*, Province*)));
	// Connect the cursor signal so that childs can update their cursors
	QObject::connect(this, SIGNAL(cursorChanged(const QCursor&)), item, SLOT(SetCursor(const QCursor&)));

	if (scene())
	{
		// Add item to scene
		item->AddToScene(scene());
	}

	// Insert land into map
	return Map::InsertLand(item);
}

Land* MapWidget::InsertNewLand(const std::string& name)
{
	return InsertLand( new MapLandItem(this, name));
}

Land* MapWidget::InsertNewLand(const Land& land)
{
	return InsertLand( new MapLandItem(this, land));
}

void MapWidget::resizeEvent(QResizeEvent* e)
{
	// Update the scene rectangle
	setSceneRect( boundingRect() );
}

void MapWidget::wheelEvent(QWheelEvent *e)
{
	// Scale the graphics view
    scaleView(pow((double)2, e->delta() / 240.0));
}

void MapWidget::keyPressEvent(QKeyEvent *e)
 {
	 // Catch '+' and '-' keypresses to scale the map
     switch (e->key()) 
	 {
		 case Qt::Key_Plus:
			 scaleView(1.2);
			 break;
		 case Qt::Key_Minus:
			 scaleView(1 / 1.2);
			 break;
	     default:
		     QGraphicsView::keyPressEvent(e);
     }
 }


void MapWidget::scaleView(qreal scaleFactor)
{
	// Scale the view matrix
	qreal factor = matrix().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width();
	// Make sure its not going to be too large or too small
	if (factor < 0.07 || factor > 100)
		return;

	// Now do the scale
	scale(scaleFactor, scaleFactor);
}

QRectF MapWidget::boundingRect() const
{
	// Return the bounding rectangle of the map
	int xmin = 0;
	int xmax = 0;
	int ymin = 0;
	int ymax = 0;

	std::list<Land*>::const_iterator landIt;

	bool gotFirstLand = false;

	for(landIt = lands.begin(); landIt != lands.end(); ++landIt)
	{
		const MapLandItem* land = (const MapLandItem*)*landIt;

		// Bounding rectangle is the bounding rectangle of all lands combined
		const QRectF bounds = land->boundingRect();
		int x0 = bounds.x();
		int x1 = x0 + bounds.width();
		int y0 = bounds.y();
		int y1 = y0 + bounds.height();

		
		// Initialize step
		if (!gotFirstLand)
		{
			gotFirstLand = true;
			xmin = x0;
			xmax = x1;
			ymin = y0;
			ymax = y1;
		}
		else
		{
			xmin = min(xmin, x0);
			xmax = max(xmax, x1);
			ymin = min(ymin, y0);
			ymax = max(ymax, y1);
		}
	}

	return QRectF(xmin, ymin, (xmax-xmin), (ymax-ymin));
}

void MapWidget::slotClickedProvince(Land *land, Province *province)
{
	// Notify listeners that the user clicked on a province
	emit clickedProvince(this, land, province);
}

void MapWidget::SetCursor(const QCursor& cursor)
{
	// Notify listeners that the user selected a new cursor
	emit cursorChanged(cursor);
}


